
const downloadGitRepo = require('../utils/download-git-repo');
const { getRepoList, createWarehouse } = require('../utils/http');
const execCommands = require('../utils/exec-commands');
const { loading, stopLoading, loadingSucceed, loadingFailed, print, printSuccess, printWarning, printError } = require('../utils/message-box');

const fs = require('fs-extra');
const path = require('path');
const inquirer = require('inquirer');

const askUser = async (choices, message = '请选择') => {
    const { choice } = await inquirer.prompt({ name: 'choice', type: 'list', choices, message });
    return choice;
};

const checkDirectory = async (targetDirectory, name, options) => {
    // 目录不存在
    if (!fs.existsSync(targetDirectory)) return;
    // 传入了 -f (强制创建)
    if (options.force) {
        await fs.remove(targetDirectory);
        return;
    }
    const choices = [
        { name: `移除并重新创建 ${name}`, value: 'overwrite' },
        { name: '取消创建', value: 'cancel' },
    ];
    const choice = await askUser(choices, `检测到当前目录已存在 ${name}，请选择:`);
    loading('Removing...');
    try {
        if (choice === 'overwrite') {
            await fs.remove(targetDirectory);
            stopLoading();
            return;
        }
    } catch (error) {
        printWarning(`目标文件夹 ${name} 移除失败！请手动删除`);
        process.exit(1);
    }
    stopLoading();
};

// 获取仓库模板项目列表
const getTemplateProject = async () => {
    const repos = await getRepoList();
    const templateProjects = (repos || {}).projects;
    if (!templateProjects && !templateProjects.length) {
        printError('读取远程仓库的模板项目失败！');
        process.exit(1);
    }
    return templateProjects.map((d) => ({ name: `${d.name}（${d.description}）`, value: d })).concat([{ name: 'Exit', value: null }]);
};

// 询问用户是否需要使用 nvm 切换 Node 版本
const chooseNodeVersion = async () => {
    const choices = [{ name: 'YES' }, { name: 'NO' }];
    const choice = await askUser(choices, '是否需要使用 nvm 切换 Node 版本?');
    if (choice === 'NO') return;
    const res = await execCommands('nvm ls', { showSuccessTips: false });
    const nodeVersions = res[0].stdout.split('\n').map(name => {
        const match = name.match(/\b(\d+\.\d+\.\d+)\b/);
        const value = (match || [])[0] || '';
        return { name: name.trim(), value };
    }).filter(({ value }) => value);
    const version = await askUser(nodeVersions, '请选择需要切换的 Node 版本：');
    await execCommands(`nvm use ${version}`, { successTips: 'Node 版本切换成功' });
    print(`当前版本：\n${version}`);
};

// 询问用户是否需要新建远程仓库
whetherCreateWarehouse = (name) => {
    let projectName = name.split('\\');
    projectName = projectName[projectName.length - 1] || name;
    return new Promise(async (resolve) => {
        const choices = [{ name: 'YES' }, { name: 'NO' }];
        const choice = await askUser(choices, '是否需要在 GitLab 新建远程仓库?');
        if (choice === 'NO') return resolve();
        inquirer.prompt([{ type: 'input', name: 'description', message: `请完善仓库信息：\n仓库名称：${projectName}\n请输入仓库描述：` }]).then(async ({ description = '' }) => {
            inquirer.prompt([{ type: 'input', name: 'namespace_id', message: `请输入仓库目录ID（默认为156，"Frontend"文件夹）` }]).then(async ({ namespace_id = 156 }) => {
                let res;
                try { res = await createWarehouse({ name: projectName, namespace_id, description }); } catch (error) { printError('新建远程仓库失败！请检查当前用户在该目录是否有操作权限'); print(`error: ${JSON.stringify(error)}`); }
                resolve(res);
            });
        });
    });
};

// 询问用户是否需要初始化 git
const whetherInitGit = async (targetDir, name) => {
    const choices = [{ name: 'YES' }, { name: 'NO' }];
    const choice = await askUser(choices, '是否需要初始化 Git ?');
    if (choice === 'NO') return;
    await execCommands(`cd ${targetDir} && git init`, { showSuccessTips: false });
    const warehouseInfo = await whetherCreateWarehouse(name);
    if (warehouseInfo && warehouseInfo.http_url_to_repo) {
        await execCommands(`cd ${targetDir} && git remote add origin ${warehouseInfo.http_url_to_repo}`);
        await execCommands(`cd ${targetDir} && git add -A`);
        await execCommands(`cd ${targetDir} && git commit -m "Initial commit"`);
        await execCommands(`cd ${targetDir} && git push -u origin master`);
    }
    const res = await execCommands(`cd ${targetDir} && git config --list`, { successTips: 'git 初始化完成，初始化信息如下：' });
    print(((res || {})[0] || {}).stdout || '');
};

// 询问用户是否需要安装项目依赖
const whetherInstallModules = async (targetDir) => {
    const choices = [{ name: 'YES' }, { name: 'NO' }];
    const choice = await askUser(choices, '是否需要安装项目依赖?');
    if (choice === 'NO') return;
    await chooseNodeVersion();
    const commands = [
        { name: 'cnpm install' },
        { name: 'npm install --registry=https://registry.npm.taobao.org' },
        { name: 'npm install' },
    ];
    const command = await askUser(commands, '请选择依赖的安装方式：');
    await execCommands(`cd ${targetDir} && ${command}`, { showSuccessTips: false });
};

// 询问用户是否需要启动项目
const whetherRunPro = async (targetDir, name) => {
    try {
        const packages = require(`${targetDir}/package.json`);
        const runKey = packages.scripts.dev ? 'dev' : (packages.scripts.serve ? 'serve' : '');
        if (!runKey) return;
        const choices = [{ name: 'YES' }, { name: 'NO' }];
        const choice = await askUser(choices, '是否需要运行项目?');
        if (choice === 'NO') return;
        execCommands(`cd ${targetDir} && npm run ${runKey}`, { loadingTips: `${name} is running now...` });
    } catch (error) { }
};

// 询问用户选择哪个模板项目并 clone 至本地
const chooseTemplateProject = async (projects, targetDir) => {
    const choice = await askUser(projects, '请选择一个项目模板');
    if (!choice) process.exit(1);
    await downloadGitRepo(`direct:${choice.http_url_to_repo}`, targetDir, { clone: true });
};

module.exports = async (name, options) => {
    const targetDirectory = path.join(process.cwd(), name);
    await checkDirectory(targetDirectory, name, options);
    const templateProjects = await getTemplateProject();
    await chooseTemplateProject(templateProjects, targetDirectory);
    if (options.git) await whetherInitGit(targetDirectory, name);
    if (!options.uninstall) await whetherInstallModules(targetDirectory);
    if (!options.unrun) await whetherRunPro(targetDirectory, name);
};